﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace QaaSimulation.QSim.Ships.Editor
{
    public class QShipModelEditorControl : Control
    {
        public enum QEditMode
        {
            Default,
            Remove,
            Add
        }

        public enum QAddType
        {
            Cockpit,
            Quarters,
            EngineRoom,
            Turrets,
            Engine,
            Armor,
            ShieldGenerator
        }

        private QShipModel m_BoundModel = null;
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public QShipModel BoundModel
        {
            get
            {
                return m_BoundModel;
            }
            set
            {
                m_BoundModel = value;
            }
        }

        private QEditMode m_EditMode;
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public QEditMode EditMode
        {
            get
            {
                return m_EditMode;
            }
            private set
            {
                m_EditMode = value;
                Invalidate();
            }
        }

        private QAddType m_AddingType;
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public QAddType AddingType
        {
            get
            {
                return m_AddingType;
            }
            private set
            {
                m_AddingType = value;
                if(m_EditMode == QEditMode.Add)
                    Invalidate();
            }
        }

        private Boolean m_ShowCentroid;
        public Boolean ShowCentroid
        {
            get
            {
                return m_ShowCentroid;
            }
            private set
            {
                m_ShowCentroid = value;
                Invalidate();
            }
        }
        private void ApplyModel()
        {
        }

        public QShipModelEditorControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
            m_CameraTranslation = new PointF();
            m_CameraScaling = 1;
            m_EditMode = QEditMode.Default;
        }

        private PointF m_CameraTranslation;
        private float m_CameraScaling;

        private PointF m_LastMousePosition;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus();
            QHitTestResult hitResult = HitTest(e.Location);
            Console.WriteLine(hitResult.ToString());

            switch (m_EditMode)
            {
                case QEditMode.Default:
                    break;
                case QEditMode.Remove:
                    if (hitResult.Box != null)
                    {
                        m_BoundModel.SetModelBox(hitResult.X, hitResult.Y, null);
                        Invalidate();
                    }
                    break;
                case QEditMode.Add:
                    HandleAddMouseDown(hitResult);
                    break;
                default:
                    break;
            }
        }

        private void HandleAddMouseDown(QHitTestResult hitResult)
        {
            if (hitResult.X != -1 && hitResult.Y != -1)
            {
                QShipBox newBox = null;
                switch (m_AddingType)
                {
                    case QAddType.Cockpit:
                        newBox = new QCockpitBox();
                        break;
                    case QAddType.Quarters:
                        newBox = new QQuartersBox();
                        break;
                    case QAddType.EngineRoom:
                        newBox = new QEngineRoomBox();
                        break;
                    case QAddType.Turrets:
                        newBox = new QTurretBox();
                        break;
                    case QAddType.Engine:
                        newBox = new QEngineBox();
                        break;
                    case QAddType.Armor:
                        newBox = new QArmorBox();
                        break;
                    case QAddType.ShieldGenerator:
                        newBox = new QShieldGeneratorBox();
                        break;
                    default:
                        break;
                }
                QShipBox[] hood = m_BoundModel.GetNeighborhood(hitResult.X, hitResult.Y);
                if(newBox.CanBePlaced(hood))
                    m_BoundModel.SetModelBox(hitResult.X, hitResult.Y, newBox);
                Invalidate();
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            switch (e.KeyCode)
            {
                case Keys.D1:
                    EditMode = QEditMode.Default;
                    break;
                case Keys.D2:
                    EditMode = QEditMode.Add;
                    break;
                case Keys.D3:
                    EditMode = QEditMode.Remove;
                    break;
                case Keys.C:
                    AddingType = QAddType.Cockpit;
                    break;
                case Keys.Q:
                    AddingType = QAddType.Quarters;
                    break;
                case Keys.R:
                    AddingType = QAddType.EngineRoom;
                    break;
                case Keys.E:
                    AddingType = QAddType.Engine;
                    break;
                case Keys.T:
                    AddingType = QAddType.Turrets;
                    break;
                case Keys.S:
                    AddingType = QAddType.ShieldGenerator;
                    break;
                case Keys.A:
                    AddingType = QAddType.Armor;
                    break;
                case Keys.F1:
                    ShowCentroid = !ShowCentroid;
                    break;
                default:
                    break;
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (m_EditMode == QEditMode.Default)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    PointF dif = new PointF(e.X - m_LastMousePosition.X, e.Y - m_LastMousePosition.Y);
                    if (!dif.IsEmpty)
                    {
                        m_CameraTranslation.X += dif.X;
                        m_CameraTranslation.Y += dif.Y;
                        Invalidate();
                    }
                }
            }

            m_LastMousePosition = e.Location;
        }

        public QHitTestResult HitTest(Point point)
        {
            PointF relPoint = new Point();
            relPoint.X = point.X - m_CameraTranslation.X;
            relPoint.Y = point.Y - m_CameraTranslation.Y;

            Point arrayPoint = new Point((int)(relPoint.X / QModelBox.BOX_RELATION), (int)(relPoint.Y / QModelBox.BOX_RELATION));
            if (arrayPoint.X < 0 || arrayPoint.X >= m_BoundModel.Width || arrayPoint.Y < 0 || arrayPoint.Y >= m_BoundModel.Height)
            {
                arrayPoint.X = -1;
                arrayPoint.Y = -1;
                return new QHitTestResult(arrayPoint, null);
            }
            QModelBox hittedBox = m_BoundModel.GetModelBox(arrayPoint.X, arrayPoint.Y);
            return new QHitTestResult(arrayPoint, hittedBox); 
        }

        public class QHitTestResult
        {
            private QModelBox m_Box;
            public QModelBox Box
            {
                get
                {
                    return m_Box;
                }
                private set
                {
                    m_Box = value;
                }
            }

            private Point m_ArrayPosition;
            public Point ArrayPosition
            {
                get
                {
                    return m_ArrayPosition;
                }
                private set
                {
                    m_ArrayPosition = value;
                }
            }

            public int X
            {
                get
                {
                    return m_ArrayPosition.X;
                }
                private set
                {
                    m_ArrayPosition.X = value;
                }
            }

            public int Y
            {
                get
                {
                    return m_ArrayPosition.Y;
                }
                private set
                {
                    m_ArrayPosition.Y = value;
                }
            }

            public QHitTestResult(Point position, QModelBox box)
            {
                m_ArrayPosition = position;
                m_Box = box;
            }

            public QHitTestResult(int x, int y, QModelBox box)
            {
                m_ArrayPosition.X = x;
                m_ArrayPosition.Y = y;
                m_Box = box;
            }

            public override string ToString()
            {
                return "QHitTestResult, " + "X : " + X + ", Y : " + Y + ", Box : " +(Box != null ? Box.ToString() : "");
            }
        }

        private void PaintHelp(Graphics g)
        {
            Font activeFont = new Font(Font.FontFamily, Font.Size, FontStyle.Bold);
            Font usedFont = this.Font;
            g.DrawString("Modes: ", usedFont, Brushes.Lime, 10, 10);
            if (m_EditMode == QEditMode.Default)
                usedFont = activeFont;
            else
                usedFont = this.Font;
            g.DrawString(" Default: 1", usedFont, Brushes.Lime, 10, 25);

            if (m_EditMode == QEditMode.Add)
                usedFont = activeFont;
            else
                usedFont = this.Font;
            g.DrawString(" Adding: 2", usedFont, Brushes.Lime, 10, 40);

            if (m_EditMode == QEditMode.Remove)
                usedFont = activeFont;
            else
                usedFont = this.Font;
            g.DrawString(" Removing: 3", usedFont, Brushes.Lime, 10, 55);

            if (m_EditMode == QEditMode.Add)
            {
                int y = 10;
                g.DrawString("Ship-Parts: ", usedFont, Brushes.Lime, 100, y);
                y += 15;

                if (m_AddingType == QAddType.Cockpit)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Cockpit: C", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.EngineRoom)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Engineroom: R", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.Quarters)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Quarters: Q", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.Turrets)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Turrets: T", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.Engine)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Engines: E", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.ShieldGenerator)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Shieldgenerator: S", usedFont, Brushes.Lime, 100, y);
                y += 15;
                if (m_AddingType == QAddType.Armor)
                    usedFont = activeFont;
                else
                    usedFont = this.Font;
                g.DrawString(" Armor: A", usedFont, Brushes.Lime, 100, y);
                y += 15;
            }

        }

        private void PaintModelInformations(Graphics g)
        {
            Font activeFont = new Font(Font.FontFamily, Font.Size, FontStyle.Bold);
            Font usedFont = this.Font;

            Rectangle box = Rectangle.FromLTRB((int)g.ClipBounds.Right - 120, (int)g.ClipBounds.Top, (int)g.ClipBounds.Right, (int)g.ClipBounds.Top + 250);
            g.FillRectangle(Brushes.Black, box);
            g.DrawRectangle(Pens.LightGray, box);
            
            int y = 10;
            g.DrawString("Informations: ", usedFont, Brushes.Lime, box.Left + 10, y);
            y += 15;
            g.DrawString(" Energy: " + m_BoundModel.TotalEnergy, usedFont, Brushes.Lime, box.Left + 10, y);
            y += 15;
            g.DrawString(" Crew: " + m_BoundModel.TotalCrew, usedFont, Brushes.Lime, box.Left + 10, y);
            y += 15;
            g.DrawString(" Mass: " + m_BoundModel.TotalMass, usedFont, Brushes.Lime, box.Left + 10, y);
            y += 15;
            g.DrawString(" Shieldpower: " + m_BoundModel.TotalShieldPower, usedFont, Brushes.Lime, box.Left + 10, y);  
        }

        private void PaintCentroid(Graphics g)
        {
            g.DrawLine(Pens.Lime, g.ClipBounds.Left, m_BoundModel.Centroid.Y, g.ClipBounds.Right, m_BoundModel.Centroid.Y);
            g.DrawLine(Pens.Lime, m_BoundModel.Centroid.X, g.ClipBounds.Top, m_BoundModel.Centroid.X, g.ClipBounds.Bottom);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.TranslateTransform(m_CameraTranslation.X, m_CameraTranslation.Y);
            g.ScaleTransform(m_CameraScaling, m_CameraScaling);
            if (m_BoundModel != null)
            {
                for (int x = 0; x < m_BoundModel.Width; x++)
                {
                    for (int y = 0; y < m_BoundModel.Height; y++)
                    {
                        e.Graphics.DrawRectangle(Pens.LightGray, new Rectangle(x * QModelBox.BOX_RELATION, y * QModelBox.BOX_RELATION, QModelBox.BOX_RELATION, QModelBox.BOX_RELATION));
                    }
                }
                for (int x = 0; x < m_BoundModel.Width; x++)
                {
                    for (int y = 0; y < m_BoundModel.Height; y++)
                    {
                        QModelBox thisBox = m_BoundModel.GetModelBox(x, y);
                        if (thisBox != null)
                        {
                            GraphicsState state = e.Graphics.Save();
                            e.Graphics.TranslateTransform(x * QModelBox.BOX_RELATION, y * QModelBox.BOX_RELATION);
                            thisBox.Paint(e.Graphics);
                            e.Graphics.Restore(state);
                        }
                    }
                }
                if (m_ShowCentroid)
                    PaintCentroid(g);
            }
            g.ResetTransform();
            PaintHelp(g);
            PaintModelInformations(g);
        }
    }
}
